package com.gmcloud.common.excel.handler;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.converters.localdatetime.LocalDateNumberConverter;
import com.alibaba.excel.converters.localdatetime.LocalDateTimeStringConverter;
import com.gmcloud.common.excel.annotation.RequestExcel;
import com.gmcloud.common.excel.listener.ListAnalysisEventListener;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.List;

/**
 * @author zl
 * @since  2022/9/20 20:46
 * @BelongsProject gm-cloud
 * @BelongsPackage com.gmcloud.common.handler
 * @description 参数解析解析器,上传excel 解析注解
 */
public class RequestExcelArgumentResolver implements HandlerMethodArgumentResolver {

    /**
     * 判断Controller层中的参数，是否满足条件，满足条件则执行resolveArgument方法，不满足则跳过
     *
     * @param parameter the method parameter to check
     * @return boolean
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestExcel.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        Class<?> parameterType = parameter.getParameterType();
        if (!parameterType.isAssignableFrom(List.class)) {
            throw new IllegalArgumentException("Excel upload request resolver error, @RequestExcel parameter is not List " + parameterType);
        }


        RequestExcel requestExcel = parameter.getParameterAnnotation(RequestExcel.class);
        assert requestExcel != null;

        Class<? extends ListAnalysisEventListener> readListenerClass = requestExcel.readListener();
        ListAnalysisEventListener<?> readListener = BeanUtils.instantiateClass(readListenerClass);

        // 获取请求文件流
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        assert request != null;
        InputStream inputStream;
        if (request instanceof MultipartRequest) {
            MultipartFile file = ((MultipartRequest) request).getFile(requestExcel.fileName());
            assert file != null;
            inputStream = file.getInputStream();
        } else {
            inputStream = request.getInputStream();
        }

        // 设置数据库保存服务
        Class<?> saveService = requestExcel.saveService();
        if (saveService != Class.class) {
            readListener.setSaveService(saveService);
        }
        // 获取目标类型
        Class<?> excelModelClass = ResolvableType.forMethodParameter(parameter).getGeneric(0).resolve();

        // 这里需要指定读用哪个 class 去读，然后读取第一个 sheet 文件流会自动关闭
        EasyExcelFactory.read(inputStream, excelModelClass, readListener)
                .registerConverter(new LocalDateTimeStringConverter())
                .registerConverter(new LocalDateNumberConverter())
                .ignoreEmptyRow(requestExcel.ignoreEmptyRow())
                .sheet().doRead();

        // 校验失败的数据处理 交给 BindResult
        WebDataBinder dataBinder = binderFactory.createBinder(webRequest, readListener.getErrors(), "excel");
        ModelMap model = mavContainer.getModel();
        model.put(BindingResult.MODEL_KEY_PREFIX + "excel", dataBinder.getBindingResult());

        return readListener.getList();
    }
}
